home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / lisp / stk-3.002 / stk-3 / STk-3.1 / Tk / generic / tkCanvArc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-31  |  51.0 KB  |  1,725 lines

  1. /* 
  2.  * tkCanvArc.c --
  3.  *
  4.  *    This file implements arc items for canvas widgets.
  5.  *
  6.  * Copyright (c) 1992-1994 The Regents of the University of California.
  7.  * Copyright (c) 1994-1995 Sun Microsystems, Inc.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  * SCCS: @(#) tkCanvArc.c 1.32 96/02/17 16:59:09
  13.  */
  14.  
  15. #include <stdio.h>
  16. #include "tkPort.h"
  17. #include "tkInt.h"
  18.  
  19. /*
  20.  * The structure below defines the record for each arc item.
  21.  */
  22.  
  23. typedef struct ArcItem  {
  24.     Tk_Item header;        /* Generic stuff that's the same for all
  25.                  * types.  MUST BE FIRST IN STRUCTURE. */
  26.     double bbox[4];        /* Coordinates (x1, y1, x2, y2) of bounding
  27.                  * box for oval of which arc is a piece. */
  28.     double start;        /* Angle at which arc begins, in degrees
  29.                  * between 0 and 360. */
  30.     double extent;        /* Extent of arc (angular distance from
  31.                  * start to end of arc) in degrees between
  32.                  * -360 and 360. */
  33.     double *outlinePtr;        /* Points to (x,y) coordinates for points
  34.                  * that define one or two closed polygons
  35.                  * representing the portion of the outline
  36.                  * that isn't part of the arc (the V-shape
  37.                  * for a pie slice or a line-like segment
  38.                  * for a chord).  Malloc'ed. */
  39.     int numOutlinePoints;    /* Number of points at outlinePtr.  Zero
  40.                  * means no space allocated. */
  41.     int width;            /* Width of outline (in pixels). */
  42.     XColor *outlineColor;    /* Color for outline.  NULL means don't
  43.                  * draw outline. */
  44.     XColor *fillColor;        /* Color for filling arc (used for drawing
  45.                  * outline too when style is "arc").  NULL
  46.                  * means don't fill arc. */
  47.     Pixmap fillStipple;        /* Stipple bitmap for filling item. */
  48.     Pixmap outlineStipple;    /* Stipple bitmap for outline. */
  49.     Tk_Uid style;        /* How to draw arc: arc, chord, or pieslice. */
  50.     GC outlineGC;        /* Graphics context for outline. */
  51.     GC fillGC;            /* Graphics context for filling item. */
  52.     double center1[2];        /* Coordinates of center of arc outline at
  53.                  * start (see ComputeArcOutline). */
  54.     double center2[2];        /* Coordinates of center of arc outline at
  55.                  * start+extent (see ComputeArcOutline). */
  56. } ArcItem;
  57.  
  58. /*
  59.  * The definitions below define the sizes of the polygons used to
  60.  * display outline information for various styles of arcs:
  61.  */
  62.  
  63. #define CHORD_OUTLINE_PTS    7
  64. #define PIE_OUTLINE1_PTS    6
  65. #define PIE_OUTLINE2_PTS    7
  66.  
  67. /*
  68.  * Information used for parsing configuration specs:
  69.  */
  70.  
  71. static Tk_CustomOption tagsOption = {Tk_CanvasTagsParseProc,
  72.     Tk_CanvasTagsPrintProc, (ClientData) NULL
  73. };
  74.  
  75. static Tk_ConfigSpec configSpecs[] = {
  76.     {TK_CONFIG_DOUBLE, "-extent", (char *) NULL, (char *) NULL,
  77.     "90", Tk_Offset(ArcItem, extent), TK_CONFIG_DONT_SET_DEFAULT},
  78.     {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL,
  79.     (char *) NULL, Tk_Offset(ArcItem, fillColor), TK_CONFIG_NULL_OK},
  80.     {TK_CONFIG_COLOR, "-outline", (char *) NULL, (char *) NULL,
  81.     "black", Tk_Offset(ArcItem, outlineColor), TK_CONFIG_NULL_OK},
  82.     {TK_CONFIG_BITMAP, "-outlinestipple", (char *) NULL, (char *) NULL,
  83.     (char *) NULL, Tk_Offset(ArcItem, outlineStipple), TK_CONFIG_NULL_OK},
  84.     {TK_CONFIG_DOUBLE, "-start", (char *) NULL, (char *) NULL,
  85.     "0", Tk_Offset(ArcItem, start), TK_CONFIG_DONT_SET_DEFAULT},
  86.     {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL,
  87.     (char *) NULL, Tk_Offset(ArcItem, fillStipple), TK_CONFIG_NULL_OK},
  88.     {TK_CONFIG_UID, "-style", (char *) NULL, (char *) NULL,
  89.     "pieslice", Tk_Offset(ArcItem, style), TK_CONFIG_DONT_SET_DEFAULT},
  90.     {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL,
  91.     (char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption},
  92.     {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL,
  93.     "1", Tk_Offset(ArcItem, width), TK_CONFIG_DONT_SET_DEFAULT},
  94.     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
  95.     (char *) NULL, 0, 0}
  96. };
  97.  
  98. /*
  99.  * Prototypes for procedures defined in this file:
  100.  */
  101.  
  102. static void        ComputeArcBbox _ANSI_ARGS_((Tk_Canvas canvas,
  103.                 ArcItem *arcPtr));
  104. static int        ConfigureArc _ANSI_ARGS_((Tcl_Interp *interp,
  105.                 Tk_Canvas canvas, Tk_Item *itemPtr, int argc,
  106.                 char **argv, int flags));
  107. static int        CreateArc _ANSI_ARGS_((Tcl_Interp *interp,
  108.                 Tk_Canvas canvas, struct Tk_Item *itemPtr,
  109.                 int argc, char **argv));
  110. static void        DeleteArc _ANSI_ARGS_((Tk_Canvas canvas,
  111.                 Tk_Item *itemPtr, Display *display));
  112. static void        DisplayArc _ANSI_ARGS_((Tk_Canvas canvas,
  113.                 Tk_Item *itemPtr, Display *display, Drawable dst,
  114.                 int x, int y, int width, int height));
  115. static int        ArcCoords _ANSI_ARGS_((Tcl_Interp *interp,
  116.                 Tk_Canvas canvas, Tk_Item *itemPtr, int argc,
  117.                 char **argv));
  118. static int        ArcToArea _ANSI_ARGS_((Tk_Canvas canvas,
  119.                 Tk_Item *itemPtr, double *rectPtr));
  120. static double        ArcToPoint _ANSI_ARGS_((Tk_Canvas canvas,
  121.                 Tk_Item *itemPtr, double *coordPtr));
  122. static int        ArcToPostscript _ANSI_ARGS_((Tcl_Interp *interp,
  123.                 Tk_Canvas canvas, Tk_Item *itemPtr, int prepass));
  124. static void        ScaleArc _ANSI_ARGS_((Tk_Canvas canvas,
  125.                 Tk_Item *itemPtr, double originX, double originY,
  126.                 double scaleX, double scaleY));
  127. static void        TranslateArc _ANSI_ARGS_((Tk_Canvas canvas,
  128.                 Tk_Item *itemPtr, double deltaX, double deltaY));
  129. static int        AngleInRange _ANSI_ARGS_((double x, double y,
  130.                 double start, double extent));
  131. static void        ComputeArcOutline _ANSI_ARGS_((ArcItem *arcPtr));
  132. static int        HorizLineToArc _ANSI_ARGS_((double x1, double x2,
  133.                 double y, double rx, double ry,
  134.                 double start, double extent));
  135. static int        VertLineToArc _ANSI_ARGS_((double x, double y1,
  136.                 double y2, double rx, double ry,
  137.                 double start, double extent));
  138.  
  139. /*
  140.  * The structures below defines the arc item types by means of procedures
  141.  * that can be invoked by generic item code.
  142.  */
  143.  
  144. Tk_ItemType tkArcType = {
  145.     "arc",                /* name */
  146.     sizeof(ArcItem),            /* itemSize */
  147.     CreateArc,                /* createProc */
  148.     configSpecs,            /* configSpecs */
  149.     ConfigureArc,            /* configureProc */
  150.     ArcCoords,                /* coordProc */
  151.     DeleteArc,                /* deleteProc */
  152.     DisplayArc,                /* displayProc */
  153.     0,                    /* alwaysRedraw */
  154.     ArcToPoint,                /* pointProc */
  155.     ArcToArea,                /* areaProc */
  156.     ArcToPostscript,            /* postscriptProc */
  157.     ScaleArc,                /* scaleProc */
  158.     TranslateArc,            /* translateProc */
  159.     (Tk_ItemIndexProc *) NULL,        /* indexProc */
  160.     (Tk_ItemCursorProc *) NULL,        /* icursorProc */
  161.     (Tk_ItemSelectionProc *) NULL,    /* selectionProc */
  162.     (Tk_ItemInsertProc *) NULL,        /* insertProc */
  163.     (Tk_ItemDCharsProc *) NULL,        /* dTextProc */
  164.     (Tk_ItemType *) NULL        /* nextPtr */
  165. };
  166.  
  167. #ifndef PI
  168. #    define PI 3.14159265358979323846
  169. #endif
  170.  
  171. /*
  172.  * The uid's below comprise the legal values for the "-style"
  173.  * option for arcs.
  174.  */
  175.  
  176. static Tk_Uid arcUid =  NULL;
  177. static Tk_Uid chordUid =  NULL;
  178. static Tk_Uid pieSliceUid = NULL;
  179.  
  180. /*
  181.  *--------------------------------------------------------------
  182.  *
  183.  * CreateArc --
  184.  *
  185.  *    This procedure is invoked to create a new arc item in
  186.  *    a canvas.
  187.  *
  188.  * Results:
  189.  *    A standard Tcl return value.  If an error occurred in
  190.  *    creating the item, then an error message is left in
  191.  *    interp->result;  in this case itemPtr is
  192.  *    left uninitialized, so it can be safely freed by the
  193.  *    caller.
  194.  *
  195.  * Side effects:
  196.  *    A new arc item is created.
  197.  *
  198.  *--------------------------------------------------------------
  199.  */
  200.  
  201. static int
  202. CreateArc(interp, canvas, itemPtr, argc, argv)
  203.     Tcl_Interp *interp;            /* Interpreter for error reporting. */
  204.     Tk_Canvas canvas;            /* Canvas to hold new item. */
  205.     Tk_Item *itemPtr;            /* Record to hold new item;  header
  206.                      * has been initialized by caller. */
  207.     int argc;                /* Number of arguments in argv. */
  208.     char **argv;            /* Arguments describing arc. */
  209. {
  210.     ArcItem *arcPtr = (ArcItem *) itemPtr;
  211.  
  212.     if (argc < 4) {
  213.     Tcl_AppendResult(interp, "wrong # args: should be \"",
  214.         Tk_PathName(Tk_CanvasTkwin(canvas)), " create ",
  215.         itemPtr->typePtr->name, " x1 y1 x2 y2 ?options?\"",
  216.         (char *) NULL);
  217.     return TCL_ERROR;
  218.     }
  219.  
  220.     /*
  221.      * Carry out once-only initialization.
  222.      */
  223.  
  224.     if (arcUid == NULL) {
  225.     arcUid = Tk_GetUid("arc");
  226.     chordUid = Tk_GetUid("chord");
  227.     pieSliceUid = Tk_GetUid("pieslice");
  228.     }
  229.  
  230.     /*
  231.      * Carry out initialization that is needed in order to clean
  232.      * up after errors during the the remainder of this procedure.
  233.      */
  234.  
  235.     arcPtr->start = 0;
  236.     arcPtr->extent = 90;
  237.     arcPtr->outlinePtr = NULL;
  238.     arcPtr->numOutlinePoints = 0;
  239.     arcPtr->width = 1;
  240.     arcPtr->outlineColor = NULL;
  241.     arcPtr->fillColor = NULL;
  242.     arcPtr->fillStipple = None;
  243.     arcPtr->outlineStipple = None;
  244.     arcPtr->style = pieSliceUid;
  245.     arcPtr->outlineGC = None;
  246.     arcPtr->fillGC = None;
  247.  
  248.     /*
  249.      * Process the arguments to fill in the item record.
  250.      */
  251.  
  252.     if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &arcPtr->bbox[0]) != TCL_OK)
  253.         || (Tk_CanvasGetCoord(interp, canvas, argv[1],
  254.         &arcPtr->bbox[1]) != TCL_OK)
  255.         || (Tk_CanvasGetCoord(interp, canvas, argv[2],
  256.             &arcPtr->bbox[2]) != TCL_OK)
  257.         || (Tk_CanvasGetCoord(interp, canvas, argv[3],
  258.             &arcPtr->bbox[3]) != TCL_OK)) {
  259.     return TCL_ERROR;
  260.     }
  261.  
  262.     if (ConfigureArc(interp, canvas, itemPtr, argc-4, argv+4, 0) != TCL_OK) {
  263.     DeleteArc(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas)));
  264.     return TCL_ERROR;
  265.     }
  266.     return TCL_OK;
  267. }
  268.  
  269. /*
  270.  *--------------------------------------------------------------
  271.  *
  272.  * ArcCoords --
  273.  *
  274.  *    This procedure is invoked to process the "coords" widget
  275.  *    command on arcs.  See the user documentation for details
  276.  *    on what it does.
  277.  *
  278.  * Results:
  279.  *    Returns TCL_OK or TCL_ERROR, and sets interp->result.
  280.  *
  281.  * Side effects:
  282.  *    The coordinates for the given item may be changed.
  283.  *
  284.  *--------------------------------------------------------------
  285.  */
  286.  
  287. static int
  288. ArcCoords(interp, canvas, itemPtr, argc, argv)
  289.     Tcl_Interp *interp;            /* Used for error reporting. */
  290.     Tk_Canvas canvas;            /* Canvas containing item. */
  291.     Tk_Item *itemPtr;            /* Item whose coordinates are to be
  292.                      * read or modified. */
  293.     int argc;                /* Number of coordinates supplied in
  294.                      * argv. */
  295.     char **argv;            /* Array of coordinates: x1, y1,
  296.                      * x2, y2, ... */
  297. {
  298.     ArcItem *arcPtr = (ArcItem *) itemPtr;
  299.     char c0[TCL_DOUBLE_SPACE], c1[TCL_DOUBLE_SPACE];
  300.     char c2[TCL_DOUBLE_SPACE], c3[TCL_DOUBLE_SPACE];
  301.  
  302.     if (argc == 0) {
  303.     Tcl_PrintDouble(interp, arcPtr->bbox[0], c0);
  304.     Tcl_PrintDouble(interp, arcPtr->bbox[1], c1);
  305.     Tcl_PrintDouble(interp, arcPtr->bbox[2], c2);
  306.     Tcl_PrintDouble(interp, arcPtr->bbox[3], c3);
  307.     Tcl_AppendResult(interp, c0, " ", c1, " ", c2, " ", c3,
  308.         (char *) NULL);
  309.     } else if (argc == 4) {
  310.     if ((Tk_CanvasGetCoord(interp, canvas, argv[0],
  311.             &arcPtr->bbox[0]) != TCL_OK)
  312.         || (Tk_CanvasGetCoord(interp, canvas, argv[1],
  313.             &arcPtr->bbox[1]) != TCL_OK)
  314.         || (Tk_CanvasGetCoord(interp, canvas, argv[2],
  315.             &arcPtr->bbox[2]) != TCL_OK)
  316.         || (Tk_CanvasGetCoord(interp, canvas, argv[3],
  317.             &arcPtr->bbox[3]) != TCL_OK)) {
  318.         return TCL_ERROR;
  319.     }
  320.     ComputeArcBbox(canvas, arcPtr);
  321.     } else {
  322.     sprintf(interp->result,
  323.         "wrong # coordinates: expected 0 or 4, got %d",
  324.         argc);
  325.     return TCL_ERROR;
  326.     }
  327.     return TCL_OK;
  328. }
  329.  
  330. /*
  331.  *--------------------------------------------------------------
  332.  *
  333.  * ConfigureArc --
  334.  *
  335.  *    This procedure is invoked to configure various aspects
  336.  *    of a arc item, such as its outline and fill colors.
  337.  *
  338.  * Results:
  339.  *    A standard Tcl result code.  If an error occurs, then
  340.  *    an error message is left in interp->result.
  341.  *
  342.  * Side effects:
  343.  *    Configuration information, such as colors and stipple
  344.  *    patterns, may be set for itemPtr.
  345.  *
  346.  *--------------------------------------------------------------
  347.  */
  348.  
  349. static int
  350. ConfigureArc(interp, canvas, itemPtr, argc, argv, flags)
  351.     Tcl_Interp *interp;        /* Used for error reporting. */
  352.     Tk_Canvas canvas;        /* Canvas containing itemPtr. */
  353.     Tk_Item *itemPtr;        /* Arc item to reconfigure. */
  354.     int argc;            /* Number of elements in argv.  */
  355.     char **argv;        /* Arguments describing things to configure. */
  356.     int flags;            /* Flags to pass to Tk_ConfigureWidget. */
  357. {
  358.     ArcItem *arcPtr = (ArcItem *) itemPtr;
  359.     XGCValues gcValues;
  360.     GC newGC;
  361.     unsigned long mask;
  362.     int i;
  363.     Tk_Window tkwin;
  364.  
  365.     tkwin = Tk_CanvasTkwin(canvas);
  366.     if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, argv,
  367.         (char *) arcPtr, flags) != TCL_OK) {
  368.     return TCL_ERROR;
  369.     }
  370.  
  371.     /*
  372.      * A few of the options require additional processing, such as
  373.      * style and graphics contexts.
  374.      */
  375.  
  376.     i = arcPtr->start/360.0;
  377.     arcPtr->start -= i*360.0;
  378.     if (arcPtr->start < 0) {
  379.     arcPtr->start += 360.0;
  380.     }
  381.     i = arcPtr->extent/360.0;
  382.     arcPtr->extent -= i*360.0;
  383.  
  384.     if ((arcPtr->style != arcUid) && (arcPtr->style != chordUid)
  385.         && (arcPtr->style != pieSliceUid)) {
  386.     Tcl_AppendResult(interp, "bad -style option \"",
  387.         arcPtr->style, "\": must be arc, chord, or pieslice",
  388.         (char *) NULL);
  389.     arcPtr->style = pieSliceUid;
  390.     return TCL_ERROR;
  391.     }
  392.  
  393.     if (arcPtr->width < 0) {
  394.     arcPtr->width = 1;
  395.     }
  396.     if (arcPtr->outlineColor == NULL) {
  397.     newGC = None;
  398.     } else {
  399.     gcValues.foreground = arcPtr->outlineColor->pixel;
  400.     gcValues.cap_style = CapButt;
  401.     gcValues.line_width = arcPtr->width;
  402.     mask = GCForeground|GCCapStyle|GCLineWidth;
  403.     if (arcPtr->outlineStipple != None) {
  404.         gcValues.stipple = arcPtr->outlineStipple;
  405.         gcValues.fill_style = FillStippled;
  406.         mask |= GCStipple|GCFillStyle;
  407.     }
  408.     newGC = Tk_GetGC(tkwin, mask, &gcValues);
  409.     }
  410.     if (arcPtr->outlineGC != None) {
  411.     Tk_FreeGC(Tk_Display(tkwin), arcPtr->outlineGC);
  412.     }
  413.     arcPtr->outlineGC = newGC;
  414.  
  415.     if ((arcPtr->fillColor == NULL) || (arcPtr->style == arcUid)) {
  416.     newGC = None;
  417.     } else {
  418.     gcValues.foreground = arcPtr->fillColor->pixel;
  419.     if (arcPtr->style == chordUid) {
  420.         gcValues.arc_mode = ArcChord;
  421.     } else {
  422.         gcValues.arc_mode = ArcPieSlice;
  423.     }
  424.     mask = GCForeground|GCArcMode;
  425.     if (arcPtr->fillStipple != None) {
  426.         gcValues.stipple = arcPtr->fillStipple;
  427.         gcValues.fill_style = FillStippled;
  428.         mask |= GCStipple|GCFillStyle;
  429.     }
  430.     newGC = Tk_GetGC(tkwin, mask, &gcValues);
  431.     }
  432.     if (arcPtr->fillGC != None) {
  433.     Tk_FreeGC(Tk_Display(tkwin), arcPtr->fillGC);
  434.     }
  435.     arcPtr->fillGC = newGC;
  436.  
  437.     ComputeArcBbox(canvas, arcPtr);
  438.     return TCL_OK;
  439. }
  440.  
  441. /*
  442.  *--------------------------------------------------------------
  443.  *
  444.  * DeleteArc --
  445.  *
  446.  *    This procedure is called to clean up the data structure
  447.  *    associated with a arc item.
  448.  *
  449.  * Results:
  450.  *    None.
  451.  *
  452.  * Side effects:
  453.  *    Resources associated with itemPtr are released.
  454.  *
  455.  *--------------------------------------------------------------
  456.  */
  457.  
  458. static void
  459. DeleteArc(canvas, itemPtr, display)
  460.     Tk_Canvas canvas;            /* Info about overall canvas. */
  461.     Tk_Item *itemPtr;            /* Item that is being deleted. */
  462.     Display *display;            /* Display containing window for
  463.                      * canvas. */
  464. {
  465.     ArcItem *arcPtr = (ArcItem *) itemPtr;
  466.  
  467.     if (arcPtr->numOutlinePoints != 0) {
  468.     ckfree((char *) arcPtr->outlinePtr);
  469.     }
  470.     if (arcPtr->outlineColor != NULL) {
  471.     Tk_FreeColor(arcPtr->outlineColor);
  472.     }
  473.     if (arcPtr->fillColor != NULL) {
  474.     Tk_FreeColor(arcPtr->fillColor);
  475.     }
  476.     if (arcPtr->fillStipple != None) {
  477.     Tk_FreeBitmap(display, arcPtr->fillStipple);
  478.     }
  479.     if (arcPtr->outlineStipple != None) {
  480.     Tk_FreeBitmap(display, arcPtr->outlineStipple);
  481.     }
  482.     if (arcPtr->outlineGC != None) {
  483.     Tk_FreeGC(display, arcPtr->outlineGC);
  484.     }
  485.     if (arcPtr->fillGC != None) {
  486.     Tk_FreeGC(display, arcPtr->fillGC);
  487.     }
  488. }
  489.  
  490. /*
  491.  *--------------------------------------------------------------
  492.  *
  493.  * ComputeArcBbox --
  494.  *
  495.  *    This procedure is invoked to compute the bounding box of
  496.  *    all the pixels that may be drawn as part of an arc.
  497.  *
  498.  * Results:
  499.  *    None.
  500.  *
  501.  * Side effects:
  502.  *    The fields x1, y1, x2, and y2 are updated in the header
  503.  *    for itemPtr.
  504.  *
  505.  *--------------------------------------------------------------
  506.  */
  507.  
  508.     /* ARGSUSED */
  509. static void
  510. ComputeArcBbox(canvas, arcPtr)
  511.     Tk_Canvas canvas;            /* Canvas that contains item. */
  512.     ArcItem *arcPtr;            /* Item whose bbox is to be
  513.                      * recomputed. */
  514. {
  515.     double tmp, center[2], point[2];
  516.  
  517.     /*
  518.      * Make sure that the first coordinates are the lowest ones.
  519.      */
  520.  
  521.     if (arcPtr->bbox[1] > arcPtr->bbox[3]) {
  522.     double tmp;
  523.     tmp = arcPtr->bbox[3];
  524.     arcPtr->bbox[3] = arcPtr->bbox[1];
  525.     arcPtr->bbox[1] = tmp;
  526.     }
  527.     if (arcPtr->bbox[0] > arcPtr->bbox[2]) {
  528.     double tmp;
  529.     tmp = arcPtr->bbox[2];
  530.     arcPtr->bbox[2] = arcPtr->bbox[0];
  531.     arcPtr->bbox[0] = tmp;
  532.     }
  533.  
  534.     ComputeArcOutline(arcPtr);
  535.  
  536.     /*
  537.      * To compute the bounding box, start with the the bbox formed
  538.      * by the two endpoints of the arc.  Then add in the center of
  539.      * the arc's oval (if relevant) and the 3-o'clock, 6-o'clock,
  540.      * 9-o'clock, and 12-o'clock positions, if they are relevant.
  541.      */
  542.  
  543.     arcPtr->header.x1 = arcPtr->header.x2 = arcPtr->center1[0];
  544.     arcPtr->header.y1 = arcPtr->header.y2 = arcPtr->center1[1];
  545.     TkIncludePoint((Tk_Item *) arcPtr, arcPtr->center2);
  546.     center[0] = (arcPtr->bbox[0] + arcPtr->bbox[2])/2;
  547.     center[1] = (arcPtr->bbox[1] + arcPtr->bbox[3])/2;
  548.     if (arcPtr->style != arcUid) {
  549.     TkIncludePoint((Tk_Item *) arcPtr, center);
  550.     }
  551.  
  552.     tmp = -arcPtr->start;
  553.     if (tmp < 0) {
  554.     tmp += 360.0;
  555.     }
  556.     if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
  557.     point[0] = arcPtr->bbox[2];
  558.     point[1] = center[1];
  559.     TkIncludePoint((Tk_Item *) arcPtr, point);
  560.     }
  561.     tmp = 90.0 - arcPtr->start;
  562.     if (tmp < 0) {
  563.     tmp += 360.0;
  564.     }
  565.     if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
  566.     point[0] = center[0];
  567.     point[1] = arcPtr->bbox[1];
  568.     TkIncludePoint((Tk_Item *) arcPtr, point);
  569.     }
  570.     tmp = 180.0 - arcPtr->start;
  571.     if (tmp < 0) {
  572.     tmp += 360.0;
  573.     }
  574.     if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
  575.     point[0] = arcPtr->bbox[0];
  576.     point[1] = center[1];
  577.     TkIncludePoint((Tk_Item *) arcPtr, point);
  578.     }
  579.     tmp = 270.0 - arcPtr->start;
  580.     if (tmp < 0) {
  581.     tmp += 360.0;
  582.     }
  583.     if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
  584.     point[0] = center[0];
  585.     point[1] = arcPtr->bbox[3];
  586.     TkIncludePoint((Tk_Item *) arcPtr, point);
  587.     }
  588.  
  589.     /*
  590.      * Lastly, expand by the width of the arc (if the arc's outline is
  591.      * being drawn) and add one extra pixel just for safety.
  592.      */
  593.  
  594.     if (arcPtr->outlineColor == NULL) {
  595.     tmp = 1;
  596.     } else {
  597.     tmp = (arcPtr->width + 1)/2 + 1;
  598.     }
  599.     arcPtr->header.x1 -= tmp;
  600.     arcPtr->header.y1 -= tmp;
  601.     arcPtr->header.x2 += tmp;
  602.     arcPtr->header.y2 += tmp;
  603. }
  604.  
  605. /*
  606.  *--------------------------------------------------------------
  607.  *
  608.  * DisplayArc --
  609.  *
  610.  *    This procedure is invoked to draw an arc item in a given
  611.  *    drawable.
  612.  *
  613.  * Results:
  614.  *    None.
  615.  *
  616.  * Side effects:
  617.  *    ItemPtr is drawn in drawable using the transformation
  618.  *    information in canvas.
  619.  *
  620.  *--------------------------------------------------------------
  621.  */
  622.  
  623. static void
  624. DisplayArc(canvas, itemPtr, display, drawable, x, y, width, height)
  625.     Tk_Canvas canvas;            /* Canvas that contains item. */
  626.     Tk_Item *itemPtr;            /* Item to be displayed. */
  627.     Display *display;            /* Display on which to draw item. */
  628.     Drawable drawable;            /* Pixmap or window in which to draw
  629.                      * item. */
  630.     int x, y, width, height;        /* Describes region of canvas that
  631.                      * must be redisplayed (not used). */
  632. {
  633.     ArcItem *arcPtr = (ArcItem *) itemPtr;
  634.     short x1, y1, x2, y2;
  635.     int start, extent;
  636.  
  637.     /*
  638.      * Compute the screen coordinates of the bounding box for the item,
  639.      * plus integer values for the angles.
  640.      */
  641.  
  642.     Tk_CanvasDrawableCoords(canvas, arcPtr->bbox[0], arcPtr->bbox[1],
  643.         &x1, &y1);
  644.     Tk_CanvasDrawableCoords(canvas, arcPtr->bbox[2], arcPtr->bbox[3],
  645.         &x2, &y2);
  646.     if (x2 <= x1) {
  647.     x2 = x1+1;
  648.     }
  649.     if (y2 <= y1) {
  650.     y2 = y1+1;
  651.     }
  652.     start = (64*arcPtr->start) + 0.5;
  653.     extent = (64*arcPtr->extent) + 0.5;
  654.  
  655.     /*
  656.      * Display filled arc first (if wanted), then outline.  If the extent
  657.      * is zero then don't invoke XFillArc or XDrawArc, since this causes
  658.      * some window servers to crash and should be a no-op anyway.
  659.      */
  660.  
  661.     if ((arcPtr->fillGC != None) && (extent != 0)) {
  662.     if (arcPtr->fillStipple != None) {
  663.         Tk_CanvasSetStippleOrigin(canvas, arcPtr->fillGC);
  664.     }
  665.     XFillArc(display, drawable, arcPtr->fillGC, x1, y1, (unsigned) (x2-x1),
  666.         (unsigned) (y2-y1), start, extent);
  667.     if (arcPtr->fillStipple != None) {
  668.         XSetTSOrigin(display, arcPtr->fillGC, 0, 0);
  669.     }
  670.     }
  671.     if (arcPtr->outlineGC != None) {
  672.     if (arcPtr->outlineStipple != None) {
  673.         Tk_CanvasSetStippleOrigin(canvas, arcPtr->outlineGC);
  674.     }
  675.     if (extent != 0) {
  676.         XDrawArc(display, drawable, arcPtr->outlineGC, x1, y1,
  677.             (unsigned) (x2-x1), (unsigned) (y2-y1), start, extent);
  678.     }
  679.  
  680.     /*
  681.      * If the outline width is very thin, don't use polygons to draw
  682.      * the linear parts of the outline (this often results in nothing
  683.      * being displayed); just draw lines instead.
  684.      */
  685.  
  686.     if (arcPtr->width <= 2) {
  687.         Tk_CanvasDrawableCoords(canvas, arcPtr->center1[0],
  688.             arcPtr->center1[1], &x1, &y1);
  689.         Tk_CanvasDrawableCoords(canvas, arcPtr->center2[0],
  690.             arcPtr->center2[1], &x2, &y2);
  691.  
  692.         if (arcPtr->style == chordUid) {
  693.         XDrawLine(display, drawable, arcPtr->outlineGC,
  694.             x1, y1, x2, y2);
  695.         } else if (arcPtr->style == pieSliceUid) {
  696.         short cx, cy;
  697.  
  698.         Tk_CanvasDrawableCoords(canvas,
  699.             (arcPtr->bbox[0] + arcPtr->bbox[2])/2.0,
  700.             (arcPtr->bbox[1] + arcPtr->bbox[3])/2.0, &cx, &cy);
  701.         XDrawLine(display, drawable, arcPtr->outlineGC,
  702.             cx, cy, x1, y1);
  703.         XDrawLine(display, drawable, arcPtr->outlineGC,
  704.             cx, cy, x2, y2);
  705.         }
  706.     } else {
  707.         if (arcPtr->style == chordUid) {
  708.         TkFillPolygon(canvas, arcPtr->outlinePtr, CHORD_OUTLINE_PTS,
  709.             display, drawable, arcPtr->outlineGC, None);
  710.         } else if (arcPtr->style == pieSliceUid) {
  711.         TkFillPolygon(canvas, arcPtr->outlinePtr, PIE_OUTLINE1_PTS,
  712.             display, drawable, arcPtr->outlineGC, None);
  713.         TkFillPolygon(canvas, arcPtr->outlinePtr + 2*PIE_OUTLINE1_PTS,
  714.             PIE_OUTLINE2_PTS, display, drawable, arcPtr->outlineGC,
  715.             None);
  716.         }
  717.     }
  718.     if (arcPtr->outlineStipple != None) {
  719.         XSetTSOrigin(display, arcPtr->outlineGC, 0, 0);
  720.     }
  721.     }
  722. }
  723.  
  724. /*
  725.  *--------------------------------------------------------------
  726.  *
  727.  * ArcToPoint --
  728.  *
  729.  *    Computes the distance from a given point to a given
  730.  *    arc, in canvas units.
  731.  *
  732.  * Results:
  733.  *    The return value is 0 if the point whose x and y coordinates
  734.  *    are coordPtr[0] and coordPtr[1] is inside the arc.  If the
  735.  *    point isn't inside the arc then the return value is the
  736.  *    distance from the point to the arc.  If itemPtr is filled,
  737.  *    then anywhere in the interior is considered "inside"; if
  738.  *    itemPtr isn't filled, then "inside" means only the area
  739.  *    occupied by the outline.
  740.  *
  741.  * Side effects:
  742.  *    None.
  743.  *
  744.  *--------------------------------------------------------------
  745.  */
  746.  
  747.     /* ARGSUSED */
  748. static double
  749. ArcToPoint(canvas, itemPtr, pointPtr)
  750.     Tk_Canvas canvas;        /* Canvas containing item. */
  751.     Tk_Item *itemPtr;        /* Item to check against point. */
  752.     double *pointPtr;        /* Pointer to x and y coordinates. */
  753. {
  754.     ArcItem *arcPtr = (ArcItem *) itemPtr;
  755.     double vertex[2], pointAngle, diff, dist, newDist;
  756.     double poly[8], polyDist, width, t1, t2;
  757.     int filled, angleInRange;
  758.  
  759.     if ((arcPtr->fillGC != None) || (arcPtr->outlineGC == None)) {
  760.     filled = 1;
  761.     } else {
  762.     filled = 0;
  763.     }
  764.  
  765.     /*
  766.      * See if the point is within the angular range of the arc.
  767.      * Remember, X angles are backwards from the way we'd normally
  768.      * think of them.  Also, compensate for any eccentricity of
  769.      * the oval.
  770.      */
  771.  
  772.     vertex[0] = (arcPtr->bbox[0] + arcPtr->bbox[2])/2.0;
  773.     vertex[1] = (arcPtr->bbox[1] + arcPtr->bbox[3])/2.0;
  774.     t1 = (pointPtr[1] - vertex[1])/(arcPtr->bbox[3] - arcPtr->bbox[1]);
  775.     t2 = (pointPtr[0] - vertex[0])/(arcPtr->bbox[2] - arcPtr->bbox[0]);
  776.     if ((t1 == 0.0) && (t2 == 0.0)) {
  777.     pointAngle = 0;
  778.     } else {
  779.     pointAngle = -atan2(t1, t2)*180/PI;
  780.     }
  781.     diff = pointAngle - arcPtr->start;
  782.     diff -= ((int) (diff/360.0) * 360.0);
  783.     if (diff < 0) {
  784.     diff += 360.0;
  785.     }
  786.     angleInRange = (diff <= arcPtr->extent) ||
  787.         ((arcPtr->extent < 0) && ((diff - 360.0) >= arcPtr->extent));
  788.  
  789.     /*
  790.      * Now perform different tests depending on what kind of arc
  791.      * we're dealing with.
  792.      */
  793.  
  794.     if (arcPtr->style == arcUid) {
  795.     if (angleInRange) {
  796.         return TkOvalToPoint(arcPtr->bbox, (double) arcPtr->width,
  797.             0, pointPtr);
  798.     }
  799.     dist = hypot(pointPtr[0] - arcPtr->center1[0],
  800.         pointPtr[1] - arcPtr->center1[1]);
  801.     newDist = hypot(pointPtr[0] - arcPtr->center2[0],
  802.         pointPtr[1] - arcPtr->center2[1]);
  803.     if (newDist < dist) {
  804.         return newDist;
  805.     }
  806.     return dist;
  807.     }
  808.  
  809.     if ((arcPtr->fillGC != None) || (arcPtr->outlineGC == None)) {
  810.     filled = 1;
  811.     } else {
  812.     filled = 0;
  813.     }
  814.     if (arcPtr->outlineGC == None) {
  815.     width = 0.0;
  816.     } else {
  817.     width = arcPtr->width;
  818.     }
  819.  
  820.     if (arcPtr->style == pieSliceUid) {
  821.     if (width > 1.0) {
  822.         dist = TkPolygonToPoint(arcPtr->outlinePtr, PIE_OUTLINE1_PTS,
  823.             pointPtr);
  824.         newDist = TkPolygonToPoint(arcPtr->outlinePtr + 2*PIE_OUTLINE1_PTS,
  825.             PIE_OUTLINE2_PTS, pointPtr);
  826.     } else {
  827.         dist = TkLineToPoint(vertex, arcPtr->center1, pointPtr);
  828.         newDist = TkLineToPoint(vertex, arcPtr->center2, pointPtr);
  829.     }
  830.     if (newDist < dist) {
  831.         dist = newDist;
  832.     }
  833.     if (angleInRange) {
  834.         newDist = TkOvalToPoint(arcPtr->bbox, width, filled, pointPtr);
  835.         if (newDist < dist) {
  836.         dist = newDist;
  837.         }
  838.     }
  839.     return dist;
  840.     }
  841.  
  842.     /*
  843.      * This is a chord-style arc.  We have to deal specially with the
  844.      * triangular piece that represents the difference between a
  845.      * chord-style arc and a pie-slice arc (for small angles this piece
  846.      * is excluded here where it would be included for pie slices;
  847.      * for large angles the piece is included here but would be
  848.      * excluded for pie slices).
  849.      */
  850.  
  851.     if (width > 1.0) {
  852.     dist = TkPolygonToPoint(arcPtr->outlinePtr, CHORD_OUTLINE_PTS,
  853.             pointPtr);
  854.     } else {
  855.     dist = TkLineToPoint(arcPtr->center1, arcPtr->center2, pointPtr);
  856.     }
  857.     poly[0] = poly[6] = vertex[0];
  858.     poly[1] = poly[7] = vertex[1];
  859.     poly[2] = arcPtr->center1[0];
  860.     poly[3] = arcPtr->center1[1];
  861.     poly[4] = arcPtr->center2[0];
  862.     poly[5] = arcPtr->center2[1];
  863.     polyDist = TkPolygonToPoint(poly, 4, pointPtr);
  864.     if (angleInRange) {
  865.     if ((arcPtr->extent < -180.0) || (arcPtr->extent > 180.0)
  866.         || (polyDist > 0.0)) {
  867.         newDist = TkOvalToPoint(arcPtr->bbox, width, filled, pointPtr);
  868.         if (newDist < dist) {
  869.         dist = newDist;
  870.         }
  871.     }
  872.     } else {
  873.     if ((arcPtr->extent < -180.0) || (arcPtr->extent > 180.0)) {
  874.         if (filled && (polyDist < dist)) {
  875.         dist = polyDist;
  876.         }
  877.     }
  878.     }
  879.     return dist;
  880. }
  881.  
  882. /*
  883.  *--------------------------------------------------------------
  884.  *
  885.  * ArcToArea --
  886.  *
  887.  *    This procedure is called to determine whether an item
  888.  *    lies entirely inside, entirely outside, or overlapping
  889.  *    a given area.
  890.  *
  891.  * Results:
  892.  *    -1 is returned if the item is entirely outside the area
  893.  *    given by rectPtr, 0 if it overlaps, and 1 if it is entirely
  894.  *    inside the given area.
  895.  *
  896.  * Side effects:
  897.  *    None.
  898.  *
  899.  *--------------------------------------------------------------
  900.  */
  901.  
  902.     /* ARGSUSED */
  903. static int
  904. ArcToArea(canvas, itemPtr, rectPtr)
  905.     Tk_Canvas canvas;        /* Canvas containing item. */
  906.     Tk_Item *itemPtr;        /* Item to check against arc. */
  907.     double *rectPtr;        /* Pointer to array of four coordinates
  908.                  * (x1, y1, x2, y2) describing rectangular
  909.                  * area.  */
  910. {
  911.     ArcItem *arcPtr = (ArcItem *) itemPtr;
  912.     double rx, ry;        /* Radii for transformed oval:  these define
  913.                  * an oval centered at the origin. */
  914.     double tRect[4];        /* Transformed version of x1, y1, x2, y2,
  915.                  * for coord. system where arc is centered
  916.                  * on the origin. */
  917.     double center[2], width, angle, tmp;
  918.     double points[20], *pointPtr;
  919.     int numPoints, filled;
  920.     int inside;            /* Non-zero means every test so far suggests
  921.                  * that arc is inside rectangle.  0 means
  922.                  * every test so far shows arc to be outside
  923.                  * of rectangle. */
  924.     int newInside;
  925.  
  926.     if ((arcPtr->fillGC != None) || (arcPtr->outlineGC == None)) {
  927.     filled = 1;
  928.     } else {
  929.     filled = 0;
  930.     }
  931.     if (arcPtr->outlineGC == None) {
  932.     width = 0.0;
  933.     } else {
  934.     width = arcPtr->width;
  935.     }
  936.  
  937.     /*
  938.      * Transform both the arc and the rectangle so that the arc's oval
  939.      * is centered on the origin.
  940.      */
  941.  
  942.     center[0] = (arcPtr->bbox[0] + arcPtr->bbox[2])/2.0;
  943.     center[1] = (arcPtr->bbox[1] + arcPtr->bbox[3])/2.0;
  944.     tRect[0] = rectPtr[0] - center[0];
  945.     tRect[1] = rectPtr[1] - center[1];
  946.     tRect[2] = rectPtr[2] - center[0];
  947.     tRect[3] = rectPtr[3] - center[1];
  948.     rx = arcPtr->bbox[2] - center[0] + width/2.0;
  949.     ry = arcPtr->bbox[3] - center[1] + width/2.0;
  950.  
  951.     /*
  952.      * Find the extreme points of the arc and see whether these are all
  953.      * inside the rectangle (in which case we're done), partly in and
  954.      * partly out (in which case we're done), or all outside (in which
  955.      * case we have more work to do).  The extreme points include the
  956.      * following, which are checked in order:
  957.      *
  958.      * 1. The outside points of the arc, corresponding to start and
  959.      *      extent.
  960.      * 2. The center of the arc (but only in pie-slice mode).
  961.      * 3. The 12, 3, 6, and 9-o'clock positions (but only if the arc
  962.      *    includes those angles).
  963.      */
  964.  
  965.     pointPtr = points;
  966.     numPoints = 0;
  967.     angle = -arcPtr->start*(PI/180.0);
  968.     pointPtr[0] = rx*cos(angle);
  969.     pointPtr[1] = ry*sin(angle);
  970.     angle += -arcPtr->extent*(PI/180.0);
  971.     pointPtr[2] = rx*cos(angle);
  972.     pointPtr[3] = ry*sin(angle);
  973.     numPoints = 2;
  974.     pointPtr += 4;
  975.  
  976.     if ((arcPtr->style == pieSliceUid) && (arcPtr->extent < 180.0)) {
  977.     pointPtr[0] = 0.0;
  978.     pointPtr[1] = 0.0;
  979.     numPoints++;
  980.     pointPtr += 2;
  981.     }
  982.  
  983.     tmp = -arcPtr->start;
  984.     if (tmp < 0) {
  985.     tmp += 360.0;
  986.     }
  987.     if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
  988.     pointPtr[0] = rx;
  989.     pointPtr[1] = 0.0;
  990.     numPoints++;
  991.     pointPtr += 2;
  992.     }
  993.     tmp = 90.0 - arcPtr->start;
  994.     if (tmp < 0) {
  995.     tmp += 360.0;
  996.     }
  997.     if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
  998.     pointPtr[0] = 0.0;
  999.     pointPtr[1] = -ry;
  1000.     numPoints++;
  1001.     pointPtr += 2;
  1002.     }
  1003.     tmp = 180.0 - arcPtr->start;
  1004.     if (tmp < 0) {
  1005.     tmp += 360.0;
  1006.     }
  1007.     if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
  1008.     pointPtr[0] = -rx;
  1009.     pointPtr[1] = 0.0;
  1010.     numPoints++;
  1011.     pointPtr += 2;
  1012.     }
  1013.     tmp = 270.0 - arcPtr->start;
  1014.     if (tmp < 0) {
  1015.     tmp += 360.0;
  1016.     }
  1017.     if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
  1018.     pointPtr[0] = 0.0;
  1019.     pointPtr[1] = ry;
  1020.     numPoints++;
  1021.     pointPtr += 2;
  1022.     }
  1023.  
  1024.     /*
  1025.      * Now that we've located the extreme points, loop through them all
  1026.      * to see which are inside the rectangle.
  1027.      */
  1028.  
  1029.     inside = (points[0] > tRect[0]) && (points[0] < tRect[2])
  1030.         && (points[1] > tRect[1]) && (points[1] < tRect[3]);
  1031.     for (pointPtr = points+2; numPoints > 1; pointPtr += 2, numPoints--) {
  1032.     newInside = (pointPtr[0] > tRect[0]) && (pointPtr[0] < tRect[2])
  1033.         && (pointPtr[1] > tRect[1]) && (pointPtr[1] < tRect[3]);
  1034.     if (newInside != inside) {
  1035.         return 0;
  1036.     }
  1037.     }
  1038.  
  1039.     if (inside) {
  1040.     return 1;
  1041.     }
  1042.  
  1043.     /*
  1044.      * So far, oval appears to be outside rectangle, but can't yet tell
  1045.      * for sure.  Next, test each of the four sides of the rectangle
  1046.      * against the bounding region for the arc.  If any intersections
  1047.      * are found, then return "overlapping".  First, test against the
  1048.      * polygon(s) forming the sides of a chord or pie-slice.
  1049.      */
  1050.  
  1051.     if (arcPtr->style == pieSliceUid) {
  1052.     if (width >= 1.0) {
  1053.         if (TkPolygonToArea(arcPtr->outlinePtr, PIE_OUTLINE1_PTS,
  1054.             rectPtr) != -1)  {
  1055.         return 0;
  1056.         }
  1057.         if (TkPolygonToArea(arcPtr->outlinePtr + 2*PIE_OUTLINE1_PTS,
  1058.             PIE_OUTLINE2_PTS, rectPtr) != -1) {
  1059.         return 0;
  1060.         }
  1061.     } else {
  1062.         if ((TkLineToArea(center, arcPtr->center1, rectPtr) != -1) ||
  1063.             (TkLineToArea(center, arcPtr->center2, rectPtr) != -1)) {
  1064.         return 0;
  1065.         }
  1066.     }
  1067.     } else if (arcPtr->style == chordUid) {
  1068.     if (width >= 1.0) {
  1069.         if (TkPolygonToArea(arcPtr->outlinePtr, CHORD_OUTLINE_PTS,
  1070.             rectPtr) != -1) {
  1071.         return 0;
  1072.         }
  1073.     } else {
  1074.         if (TkLineToArea(arcPtr->center1, arcPtr->center2,
  1075.             rectPtr) != -1) {
  1076.         return 0;
  1077.         }
  1078.     }
  1079.     }
  1080.  
  1081.     /*
  1082.      * Next check for overlap between each of the four sides and the
  1083.      * outer perimiter of the arc.  If the arc isn't filled, then also
  1084.      * check the inner perimeter of the arc.
  1085.      */
  1086.  
  1087.     if (HorizLineToArc(tRect[0], tRect[2], tRect[1], rx, ry, arcPtr->start,
  1088.         arcPtr->extent)
  1089.         || HorizLineToArc(tRect[0], tRect[2], tRect[3], rx, ry,
  1090.         arcPtr->start, arcPtr->extent)
  1091.         || VertLineToArc(tRect[0], tRect[1], tRect[3], rx, ry,
  1092.         arcPtr->start, arcPtr->extent)
  1093.         || VertLineToArc(tRect[2], tRect[1], tRect[3], rx, ry,
  1094.         arcPtr->start, arcPtr->extent)) {
  1095.     return 0;
  1096.     }
  1097.     if ((width > 1.0) && !filled) {
  1098.     rx -= width;
  1099.     ry -= width;
  1100.     if (HorizLineToArc(tRect[0], tRect[2], tRect[1], rx, ry, arcPtr->start,
  1101.             arcPtr->extent)
  1102.         || HorizLineToArc(tRect[0], tRect[2], tRect[3], rx, ry,
  1103.             arcPtr->start, arcPtr->extent)
  1104.         || VertLineToArc(tRect[0], tRect[1], tRect[3], rx, ry,
  1105.             arcPtr->start, arcPtr->extent)
  1106.         || VertLineToArc(tRect[2], tRect[1], tRect[3], rx, ry,
  1107.             arcPtr->start, arcPtr->extent)) {
  1108.         return 0;
  1109.     }
  1110.     }
  1111.  
  1112.     /*
  1113.      * The arc still appears to be totally disjoint from the rectangle,
  1114.      * but it's also possible that the rectangle is totally inside the arc.
  1115.      * Do one last check, which is to check one point of the rectangle
  1116.      * to see if it's inside the arc.  If it is, we've got overlap.  If
  1117.      * it isn't, the arc's really outside the rectangle.
  1118.      */
  1119.  
  1120.     if (ArcToPoint(canvas, itemPtr, rectPtr) == 0.0) {
  1121.     return 0;
  1122.     }
  1123.     return -1;
  1124. }
  1125.  
  1126. /*
  1127.  *--------------------------------------------------------------
  1128.  *
  1129.  * ScaleArc --
  1130.  *
  1131.  *    This procedure is invoked to rescale an arc item.
  1132.  *
  1133.  * Results:
  1134.  *    None.
  1135.  *
  1136.  * Side effects:
  1137.  *    The arc referred to by itemPtr is rescaled so that the
  1138.  *    following transformation is applied to all point
  1139.  *    coordinates:
  1140.  *        x' = originX + scaleX*(x-originX)
  1141.  *        y' = originY + scaleY*(y-originY)
  1142.  *
  1143.  *--------------------------------------------------------------
  1144.  */
  1145.  
  1146. static void
  1147. ScaleArc(canvas, itemPtr, originX, originY, scaleX, scaleY)
  1148.     Tk_Canvas canvas;            /* Canvas containing arc. */
  1149.     Tk_Item *itemPtr;            /* Arc to be scaled. */
  1150.     double originX, originY;        /* Origin about which to scale rect. */
  1151.     double scaleX;            /* Amount to scale in X direction. */
  1152.     double scaleY;            /* Amount to scale in Y direction. */
  1153. {
  1154.     ArcItem *arcPtr = (ArcItem *) itemPtr;
  1155.  
  1156.     arcPtr->bbox[0] = originX + scaleX*(arcPtr->bbox[0] - originX);
  1157.     arcPtr->bbox[1] = originY + scaleY*(arcPtr->bbox[1] - originY);
  1158.     arcPtr->bbox[2] = originX + scaleX*(arcPtr->bbox[2] - originX);
  1159.     arcPtr->bbox[3] = originY + scaleY*(arcPtr->bbox[3] - originY);
  1160.     ComputeArcBbox(canvas, arcPtr);
  1161. }
  1162.  
  1163. /*
  1164.  *--------------------------------------------------------------
  1165.  *
  1166.  * TranslateArc --
  1167.  *
  1168.  *    This procedure is called to move an arc by a given amount.
  1169.  *
  1170.  * Results:
  1171.  *    None.
  1172.  *
  1173.  * Side effects:
  1174.  *    The position of the arc is offset by (xDelta, yDelta), and
  1175.  *    the bounding box is updated in the generic part of the item
  1176.  *    structure.
  1177.  *
  1178.  *--------------------------------------------------------------
  1179.  */
  1180.  
  1181. static void
  1182. TranslateArc(canvas, itemPtr, deltaX, deltaY)
  1183.     Tk_Canvas canvas;            /* Canvas containing item. */
  1184.     Tk_Item *itemPtr;            /* Item that is being moved. */
  1185.     double deltaX, deltaY;        /* Amount by which item is to be
  1186.                      * moved. */
  1187. {
  1188.     ArcItem *arcPtr = (ArcItem *) itemPtr;
  1189.  
  1190.     arcPtr->bbox[0] += deltaX;
  1191.     arcPtr->bbox[1] += deltaY;
  1192.     arcPtr->bbox[2] += deltaX;
  1193.     arcPtr->bbox[3] += deltaY;
  1194.     ComputeArcBbox(canvas, arcPtr);
  1195. }
  1196.  
  1197. /*
  1198.  *--------------------------------------------------------------
  1199.  *
  1200.  * ComputeArcOutline --
  1201.  *
  1202.  *    This procedure creates a polygon describing everything in
  1203.  *    the outline for an arc except what's in the curved part.
  1204.  *    For a "pie slice" arc this is a V-shaped chunk, and for
  1205.  *    a "chord" arc this is a linear chunk (with cutaway corners).
  1206.  *    For "arc" arcs, this stuff isn't relevant.
  1207.  *
  1208.  * Results:
  1209.  *    None.
  1210.  *
  1211.  * Side effects:
  1212.  *    The information at arcPtr->outlinePtr gets modified, and
  1213.  *    storage for arcPtr->outlinePtr may be allocated or freed.
  1214.  *
  1215.  *--------------------------------------------------------------
  1216.  */
  1217.  
  1218. static void
  1219. ComputeArcOutline(arcPtr)
  1220.     ArcItem *arcPtr;            /* Information about arc. */
  1221. {
  1222.     double sin1, cos1, sin2, cos2, angle, halfWidth;
  1223.     double boxWidth, boxHeight;
  1224.     double vertex[2], corner1[2], corner2[2];
  1225.     double *outlinePtr;
  1226.  
  1227.     /*
  1228.      * Make sure that the outlinePtr array is large enough to hold
  1229.      * either a chord or pie-slice outline.
  1230.      */
  1231.  
  1232.     if (arcPtr->numOutlinePoints == 0) {
  1233.     arcPtr->outlinePtr = (double *) ckalloc((unsigned)
  1234.         (26 * sizeof(double)));
  1235.     arcPtr->numOutlinePoints = 22;
  1236.     }
  1237.     outlinePtr = arcPtr->outlinePtr;
  1238.  
  1239.     /*
  1240.      * First compute the two points that lie at the centers of
  1241.      * the ends of the curved arc segment, which are marked with
  1242.      * X's in the figure below:
  1243.      *
  1244.      *
  1245.      *                  * * *
  1246.      *                  *          *
  1247.      *               *      * *      *
  1248.      *             *    *         *    *
  1249.      *            *   *             *   *
  1250.      *             X *               * X
  1251.      *
  1252.      * The code is tricky because the arc can be ovular in shape.
  1253.      * It computes the position for a unit circle, and then
  1254.      * scales to fit the shape of the arc's bounding box.
  1255.      *
  1256.      * Also, watch out because angles go counter-clockwise like you
  1257.      * might expect, but the y-coordinate system is inverted.  To
  1258.      * handle this, just negate the angles in all the computations.
  1259.      */
  1260.  
  1261.     boxWidth = arcPtr->bbox[2] - arcPtr->bbox[0];
  1262.     boxHeight = arcPtr->bbox[3] - arcPtr->bbox[1];
  1263.     angle = -arcPtr->start*PI/180.0;
  1264.     sin1 = sin(angle);
  1265.     cos1 = cos(angle);
  1266.     angle -= arcPtr->extent*PI/180.0;
  1267.     sin2 = sin(angle);
  1268.     cos2 = cos(angle);
  1269.     vertex[0] = (arcPtr->bbox[0] + arcPtr->bbox[2])/2.0;
  1270.     vertex[1] = (arcPtr->bbox[1] + arcPtr->bbox[3])/2.0;
  1271.     arcPtr->center1[0] = vertex[0] + cos1*boxWidth/2.0;
  1272.     arcPtr->center1[1] = vertex[1] + sin1*boxHeight/2.0;
  1273.     arcPtr->center2[0] = vertex[0] + cos2*boxWidth/2.0;
  1274.     arcPtr->center2[1] = vertex[1] + sin2*boxHeight/2.0;
  1275.  
  1276.     /*
  1277.      * Next compute the "outermost corners" of the arc, which are
  1278.      * marked with X's in the figure below:
  1279.      *
  1280.      *                  * * *
  1281.      *                  *          *
  1282.      *               *      * *      *
  1283.      *             *    *         *    *
  1284.      *            X   *             *   X
  1285.      *               *               *
  1286.      *
  1287.      * The code below is tricky because it has to handle eccentricity
  1288.      * in the shape of the oval.  The key in the code below is to
  1289.      * realize that the slope of the line from arcPtr->center1 to corner1
  1290.      * is (boxWidth*sin1)/(boxHeight*cos1), and similarly for arcPtr->center2
  1291.      * and corner2.  These formulas can be computed from the formula for
  1292.      * the oval.
  1293.      */
  1294.  
  1295.     halfWidth = arcPtr->width/2.0;
  1296.     if (((boxWidth*sin1) == 0.0) && ((boxHeight*cos1) == 0.0)) {
  1297.     angle = 0.0;
  1298.     } else {
  1299.     angle = atan2(boxWidth*sin1, boxHeight*cos1);
  1300.     }
  1301.     corner1[0] = arcPtr->center1[0] + cos(angle)*halfWidth;
  1302.     corner1[1] = arcPtr->center1[1] + sin(angle)*halfWidth;
  1303.     if (((boxWidth*sin2) == 0.0) && ((boxHeight*cos2) == 0.0)) {
  1304.     angle = 0.0;
  1305.     } else {
  1306.     angle = atan2(boxWidth*sin2, boxHeight*cos2);
  1307.     }
  1308.     corner2[0] = arcPtr->center2[0] + cos(angle)*halfWidth;
  1309.     corner2[1] = arcPtr->center2[1] + sin(angle)*halfWidth;
  1310.  
  1311.     /*
  1312.      * For a chord outline, generate a six-sided polygon with three
  1313.      * points for each end of the chord.  The first and third points
  1314.      * for each end are butt points generated on either side of the
  1315.      * center point.  The second point is the corner point.
  1316.      */
  1317.  
  1318.     if (arcPtr->style == chordUid) {
  1319.     outlinePtr[0] = outlinePtr[12] = corner1[0];
  1320.     outlinePtr[1] = outlinePtr[13] = corner1[1];
  1321.     TkGetButtPoints(arcPtr->center2, arcPtr->center1,
  1322.         (double) arcPtr->width, 0, outlinePtr+10, outlinePtr+2);
  1323.     outlinePtr[4] = arcPtr->center2[0] + outlinePtr[2]
  1324.         - arcPtr->center1[0];
  1325.     outlinePtr[5] = arcPtr->center2[1] + outlinePtr[3]
  1326.         - arcPtr->center1[1];
  1327.     outlinePtr[6] = corner2[0];
  1328.     outlinePtr[7] = corner2[1];
  1329.     outlinePtr[8] = arcPtr->center2[0] + outlinePtr[10]
  1330.         - arcPtr->center1[0];
  1331.     outlinePtr[9] = arcPtr->center2[1] + outlinePtr[11]
  1332.         - arcPtr->center1[1];
  1333.     } else if (arcPtr->style == pieSliceUid) {
  1334.     /*
  1335.      * For pie slices, generate two polygons, one for each side
  1336.      * of the pie slice.  The first arm has a shape like this,
  1337.      * where the center of the oval is X, arcPtr->center1 is at Y, and
  1338.      * corner1 is at Z:
  1339.      *
  1340.      *     _____________________
  1341.      *    |              \
  1342.      *    |               \
  1343.      *    X             Y  Z
  1344.      *    |               /
  1345.      *    |_____________________/
  1346.      *
  1347.      */
  1348.  
  1349.     TkGetButtPoints(arcPtr->center1, vertex, (double) arcPtr->width, 0,
  1350.         outlinePtr, outlinePtr+2);
  1351.     outlinePtr[4] = arcPtr->center1[0] + outlinePtr[2] - vertex[0];
  1352.     outlinePtr[5] = arcPtr->center1[1] + outlinePtr[3] - vertex[1];
  1353.     outlinePtr[6] = corner1[0];
  1354.     outlinePtr[7] = corner1[1];
  1355.     outlinePtr[8] = arcPtr->center1[0] + outlinePtr[0] - vertex[0];
  1356.     outlinePtr[9] = arcPtr->center1[1] + outlinePtr[1] - vertex[1];
  1357.     outlinePtr[10] = outlinePtr[0];
  1358.     outlinePtr[11] = outlinePtr[1];
  1359.  
  1360.     /*
  1361.      * The second arm has a shape like this:
  1362.      *
  1363.      *
  1364.      *       ______________________
  1365.      *      /              \
  1366.      *     /               \
  1367.      *    Z  Y            X  /
  1368.      *     \              /
  1369.      *      \______________________/
  1370.      *
  1371.      * Similar to above X is the center of the oval/circle, Y is
  1372.      * arcPtr->center2, and Z is corner2.  The extra jog out to the left
  1373.      * of X is needed in or to produce a butted joint with the
  1374.      * first arm;  the corner to the right of X is one of the
  1375.      * first two points of the first arm, depending on extent.
  1376.      */
  1377.  
  1378.     TkGetButtPoints(arcPtr->center2, vertex, (double) arcPtr->width, 0,
  1379.         outlinePtr+12, outlinePtr+16);
  1380.     if ((arcPtr->extent > 180) ||
  1381.         ((arcPtr->extent < 0) && (arcPtr->extent > -180))) {
  1382.         outlinePtr[14] = outlinePtr[0];
  1383.         outlinePtr[15] = outlinePtr[1];
  1384.     } else {
  1385.         outlinePtr[14] = outlinePtr[2];
  1386.         outlinePtr[15] = outlinePtr[3];
  1387.     }
  1388.     outlinePtr[18] = arcPtr->center2[0] + outlinePtr[16] - vertex[0];
  1389.     outlinePtr[19] = arcPtr->center2[1] + outlinePtr[17] - vertex[1];
  1390.     outlinePtr[20] = corner2[0];
  1391.     outlinePtr[21] = corner2[1];
  1392.     outlinePtr[22] = arcPtr->center2[0] + outlinePtr[12] - vertex[0];
  1393.     outlinePtr[23] = arcPtr->center2[1] + outlinePtr[13] - vertex[1];
  1394.     outlinePtr[24] = outlinePtr[12];
  1395.     outlinePtr[25] = outlinePtr[13];
  1396.     }
  1397. }
  1398.  
  1399. /*
  1400.  *--------------------------------------------------------------
  1401.  *
  1402.  * HorizLineToArc --
  1403.  *
  1404.  *    Determines whether a horizontal line segment intersects
  1405.  *    a given arc.
  1406.  *
  1407.  * Results:
  1408.  *    The return value is 1 if the given line intersects the
  1409.  *    infinitely-thin arc section defined by rx, ry, start,
  1410.  *    and extent, and 0 otherwise.  Only the perimeter of the
  1411.  *    arc is checked: interior areas (e.g. pie-slice or chord)
  1412.  *    are not checked.
  1413.  *
  1414.  * Side effects:
  1415.  *    None.
  1416.  *
  1417.  *--------------------------------------------------------------
  1418.  */
  1419.  
  1420. static int
  1421. HorizLineToArc(x1, x2, y, rx, ry, start, extent)
  1422.     double x1, x2;        /* X-coords of endpoints of line segment. 
  1423.                  * X1 must be <= x2. */
  1424.     double y;            /* Y-coordinate of line segment. */
  1425.     double rx, ry;        /* These x- and y-radii define an oval
  1426.                  * centered at the origin. */
  1427.     double start, extent;    /* Angles that define extent of arc, in
  1428.                  * the standard fashion for this module. */
  1429. {
  1430.     double tmp;
  1431.     double tx, ty;        /* Coordinates of intersection point in
  1432.                  * transformed coordinate system. */
  1433.     double x;
  1434.  
  1435.     /*
  1436.      * Compute the x-coordinate of one possible intersection point
  1437.      * between the arc and the line.  Use a transformed coordinate
  1438.      * system where the oval is a unit circle centered at the origin.
  1439.      * Then scale back to get actual x-coordinate.
  1440.      */
  1441.  
  1442.     ty = y/ry;
  1443.     tmp = 1 - ty*ty;
  1444.     if (tmp < 0) {
  1445.     return 0;
  1446.     }
  1447.     tx = sqrt(tmp);
  1448.     x = tx*rx;
  1449.  
  1450.     /*
  1451.      * Test both intersection points.
  1452.      */
  1453.  
  1454.     if ((x >= x1) && (x <= x2) && AngleInRange(tx, ty, start, extent)) {
  1455.     return 1;
  1456.     }
  1457.     if ((-x >= x1) && (-x <= x2) && AngleInRange(-tx, ty, start, extent)) {
  1458.     return 1;
  1459.     }
  1460.     return 0;
  1461. }
  1462.  
  1463. /*
  1464.  *--------------------------------------------------------------
  1465.  *
  1466.  * VertLineToArc --
  1467.  *
  1468.  *    Determines whether a vertical line segment intersects
  1469.  *    a given arc.
  1470.  *
  1471.  * Results:
  1472.  *    The return value is 1 if the given line intersects the
  1473.  *    infinitely-thin arc section defined by rx, ry, start,
  1474.  *    and extent, and 0 otherwise.  Only the perimeter of the
  1475.  *    arc is checked: interior areas (e.g. pie-slice or chord)
  1476.  *    are not checked.
  1477.  *
  1478.  * Side effects:
  1479.  *    None.
  1480.  *
  1481.  *--------------------------------------------------------------
  1482.  */
  1483.  
  1484. static int
  1485. VertLineToArc(x, y1, y2, rx, ry, start, extent)
  1486.     double x;            /* X-coordinate of line segment. */
  1487.     double y1, y2;        /* Y-coords of endpoints of line segment. 
  1488.                  * Y1 must be <= y2. */
  1489.     double rx, ry;        /* These x- and y-radii define an oval
  1490.                  * centered at the origin. */
  1491.     double start, extent;    /* Angles that define extent of arc, in
  1492.                  * the standard fashion for this module. */
  1493. {
  1494.     double tmp;
  1495.     double tx, ty;        /* Coordinates of intersection point in
  1496.                  * transformed coordinate system. */
  1497.     double y;
  1498.  
  1499.     /*
  1500.      * Compute the y-coordinate of one possible intersection point
  1501.      * between the arc and the line.  Use a transformed coordinate
  1502.      * system where the oval is a unit circle centered at the origin.
  1503.      * Then scale back to get actual y-coordinate.
  1504.      */
  1505.  
  1506.     tx = x/rx;
  1507.     tmp = 1 - tx*tx;
  1508.     if (tmp < 0) {
  1509.     return 0;
  1510.     }
  1511.     ty = sqrt(tmp);
  1512.     y = ty*ry;
  1513.  
  1514.     /*
  1515.      * Test both intersection points.
  1516.      */
  1517.  
  1518.     if ((y > y1) && (y < y2) && AngleInRange(tx, ty, start, extent)) {
  1519.     return 1;
  1520.     }
  1521.     if ((-y > y1) && (-y < y2) && AngleInRange(tx, -ty, start, extent)) {
  1522.     return 1;
  1523.     }
  1524.     return 0;
  1525. }
  1526.  
  1527. /*
  1528.  *--------------------------------------------------------------
  1529.  *
  1530.  * AngleInRange --
  1531.  *
  1532.  *    Determine whether the angle from the origin to a given
  1533.  *    point is within a given range.
  1534.  *
  1535.  * Results:
  1536.  *    The return value is 1 if the angle from (0,0) to (x,y)
  1537.  *    is in the range given by start and extent, where angles
  1538.  *    are interpreted in the standard way for ovals (meaning
  1539.  *    backwards from normal interpretation).  Otherwise the
  1540.  *    return value is 0.
  1541.  *
  1542.  * Side effects:
  1543.  *    None.
  1544.  *
  1545.  *--------------------------------------------------------------
  1546.  */
  1547.  
  1548. static int
  1549. AngleInRange(x, y, start, extent)
  1550.     double x, y;        /* Coordinate of point;  angle measured
  1551.                  * from origin to here, relative to x-axis. */
  1552.     double start;        /* First angle, degrees, >=0, <=360. */
  1553.     double extent;        /* Size of arc in degrees >=-360, <=360. */
  1554. {
  1555.     double diff;
  1556.  
  1557.     if ((x == 0.0) && (y == 0.0)) {
  1558.     return 1;
  1559.     }
  1560.     diff = -atan2(y, x);
  1561.     diff = diff*(180.0/PI) - start;
  1562.     while (diff > 360.0) {
  1563.     diff -= 360.0;
  1564.     }
  1565.     while (diff < 0.0) {
  1566.     diff += 360.0;
  1567.     }
  1568.     if (extent >= 0) {
  1569.     return diff <= extent;
  1570.     }
  1571.     return (diff-360.0) >= extent;
  1572. }
  1573.  
  1574. /*
  1575.  *--------------------------------------------------------------
  1576.  *
  1577.  * ArcToPostscript --
  1578.  *
  1579.  *    This procedure is called to generate Postscript for
  1580.  *    arc items.
  1581.  *
  1582.  * Results:
  1583.  *    The return value is a standard Tcl result.  If an error
  1584.  *    occurs in generating Postscript then an error message is
  1585.  *    left in interp->result, replacing whatever used
  1586.  *    to be there.  If no error occurs, then Postscript for the
  1587.  *    item is appended to the result.
  1588.  *
  1589.  * Side effects:
  1590.  *    None.
  1591.  *
  1592.  *--------------------------------------------------------------
  1593.  */
  1594.  
  1595. static int
  1596. ArcToPostscript(interp, canvas, itemPtr, prepass)
  1597.     Tcl_Interp *interp;            /* Leave Postscript or error message
  1598.                      * here. */
  1599.     Tk_Canvas canvas;            /* Information about overall canvas. */
  1600.     Tk_Item *itemPtr;            /* Item for which Postscript is
  1601.                      * wanted. */
  1602.     int prepass;            /* 1 means this is a prepass to
  1603.                      * collect font information;  0 means
  1604.                      * final Postscript is being created. */
  1605. {
  1606.     ArcItem *arcPtr = (ArcItem *) itemPtr;
  1607.     char buffer[400];
  1608.     double y1, y2, ang1, ang2;
  1609.  
  1610.     y1 = Tk_CanvasPsY(canvas, arcPtr->bbox[1]);
  1611.     y2 = Tk_CanvasPsY(canvas, arcPtr->bbox[3]);
  1612.     ang1 = arcPtr->start;
  1613.     ang2 = ang1 + arcPtr->extent;
  1614.     if (ang2 < ang1) {
  1615.     ang1 = ang2;
  1616.     ang2 = arcPtr->start;
  1617.     }
  1618.  
  1619.     /*
  1620.      * If the arc is filled, output Postscript for the interior region
  1621.      * of the arc.
  1622.      */
  1623.  
  1624.     if (arcPtr->fillGC != None) {
  1625.     sprintf(buffer, "matrix currentmatrix\n%.15g %.15g translate %.15g %.15g scale\n",
  1626.         (arcPtr->bbox[0] + arcPtr->bbox[2])/2, (y1 + y2)/2,
  1627.         (arcPtr->bbox[2] - arcPtr->bbox[0])/2, (y1 - y2)/2);
  1628.     Tcl_AppendResult(interp, buffer, (char *) NULL);
  1629.     if (arcPtr->style == chordUid) {
  1630.         sprintf(buffer, "0 0 1 %.15g %.15g arc closepath\nsetmatrix\n",
  1631.             ang1, ang2);
  1632.     } else {
  1633.         sprintf(buffer,
  1634.             "0 0 moveto 0 0 1 %.15g %.15g arc closepath\nsetmatrix\n",
  1635.             ang1, ang2);
  1636.     }
  1637.     Tcl_AppendResult(interp, buffer, (char *) NULL);
  1638.     if (Tk_CanvasPsColor(interp, canvas, arcPtr->fillColor) != TCL_OK) {
  1639.         return TCL_ERROR;
  1640.     };
  1641.     if (arcPtr->fillStipple != None) {
  1642.         Tcl_AppendResult(interp, "clip ", (char *) NULL);
  1643.         if (Tk_CanvasPsStipple(interp, canvas, arcPtr->fillStipple)
  1644.             != TCL_OK) {
  1645.         return TCL_ERROR;
  1646.         }
  1647.         if (arcPtr->outlineGC != None) {
  1648.         Tcl_AppendResult(interp, "grestore gsave\n", (char *) NULL);
  1649.         }
  1650.     } else {
  1651.         Tcl_AppendResult(interp, "fill\n", (char *) NULL);
  1652.     }
  1653.     }
  1654.  
  1655.     /*
  1656.      * If there's an outline for the arc, draw it.
  1657.      */
  1658.  
  1659.     if (arcPtr->outlineGC != None) {
  1660.     sprintf(buffer, "matrix currentmatrix\n%.15g %.15g translate %.15g %.15g scale\n",
  1661.         (arcPtr->bbox[0] + arcPtr->bbox[2])/2, (y1 + y2)/2,
  1662.         (arcPtr->bbox[2] - arcPtr->bbox[0])/2, (y1 - y2)/2);
  1663.     Tcl_AppendResult(interp, buffer, (char *) NULL);
  1664.     sprintf(buffer, "0 0 1 %.15g %.15g arc\nsetmatrix\n", ang1, ang2);
  1665.     Tcl_AppendResult(interp, buffer, (char *) NULL);
  1666.     sprintf(buffer, "%d setlinewidth\n0 setlinecap\n", arcPtr->width);
  1667.     Tcl_AppendResult(interp, buffer, (char *) NULL);
  1668.     if (Tk_CanvasPsColor(interp, canvas, arcPtr->outlineColor)
  1669.         != TCL_OK) {
  1670.         return TCL_ERROR;
  1671.     }
  1672.     if (arcPtr->outlineStipple != None) {
  1673.         Tcl_AppendResult(interp, "StrokeClip ", (char *) NULL);
  1674.         if (Tk_CanvasPsStipple(interp, canvas,
  1675.             arcPtr->outlineStipple) != TCL_OK) {
  1676.         return TCL_ERROR;
  1677.         }
  1678.     } else {
  1679.         Tcl_AppendResult(interp, "stroke\n", (char *) NULL);
  1680.     }
  1681.     if (arcPtr->style != arcUid) {
  1682.         Tcl_AppendResult(interp, "grestore gsave\n", (char *) NULL);
  1683.         if (arcPtr->style == chordUid) {
  1684.         Tk_CanvasPsPath(interp, canvas, arcPtr->outlinePtr,
  1685.             CHORD_OUTLINE_PTS);
  1686.         } else {
  1687.         Tk_CanvasPsPath(interp, canvas, arcPtr->outlinePtr,
  1688.             PIE_OUTLINE1_PTS);
  1689.         if (Tk_CanvasPsColor(interp, canvas, arcPtr->outlineColor)
  1690.             != TCL_OK) {
  1691.             return TCL_ERROR;
  1692.         }
  1693.         if (arcPtr->outlineStipple != None) {
  1694.             Tcl_AppendResult(interp, "clip ", (char *) NULL);
  1695.             if (Tk_CanvasPsStipple(interp, canvas,
  1696.                 arcPtr->outlineStipple) != TCL_OK) {
  1697.             return TCL_ERROR;
  1698.             }
  1699.         } else {
  1700.             Tcl_AppendResult(interp, "fill\n", (char *) NULL);
  1701.         }
  1702.         Tcl_AppendResult(interp, "grestore gsave\n", (char *) NULL);
  1703.         Tk_CanvasPsPath(interp, canvas,
  1704.             arcPtr->outlinePtr + 2*PIE_OUTLINE1_PTS,
  1705.             PIE_OUTLINE2_PTS);
  1706.         }
  1707.         if (Tk_CanvasPsColor(interp, canvas, arcPtr->outlineColor)
  1708.             != TCL_OK) {
  1709.         return TCL_ERROR;
  1710.         }
  1711.         if (arcPtr->outlineStipple != None) {
  1712.         Tcl_AppendResult(interp, "clip ", (char *) NULL);
  1713.         if (Tk_CanvasPsStipple(interp, canvas,
  1714.             arcPtr->outlineStipple) != TCL_OK) {
  1715.             return TCL_ERROR;
  1716.         }
  1717.         } else {
  1718.         Tcl_AppendResult(interp, "fill\n", (char *) NULL);
  1719.         }
  1720.     }
  1721.     }
  1722.  
  1723.     return TCL_OK;
  1724. }
  1725.